1 package android.content.res; 2 3 import static android.os.Build.VERSION_CODES.O; 4 import static android.os.Build.VERSION_CODES.Q; 5 import static android.util.TypedValue.COMPLEX_UNIT_DIP; 6 import static android.util.TypedValue.COMPLEX_UNIT_IN; 7 import static android.util.TypedValue.COMPLEX_UNIT_MM; 8 import static android.util.TypedValue.COMPLEX_UNIT_PT; 9 import static android.util.TypedValue.COMPLEX_UNIT_PX; 10 import static android.util.TypedValue.COMPLEX_UNIT_SP; 11 import static android.util.TypedValue.TYPE_FIRST_COLOR_INT; 12 import static android.util.TypedValue.TYPE_INT_BOOLEAN; 13 import static android.util.TypedValue.TYPE_INT_COLOR_ARGB8; 14 import static android.util.TypedValue.TYPE_INT_COLOR_RGB8; 15 import static android.util.TypedValue.TYPE_INT_DEC; 16 import static android.util.TypedValue.TYPE_LAST_INT; 17 import static android.util.TypedValue.TYPE_REFERENCE; 18 import static android.util.TypedValue.TYPE_STRING; 19 import static android.util.TypedValue.applyDimension; 20 import static com.google.common.truth.Truth.assertThat; 21 import static org.junit.Assert.assertThrows; 22 import static org.junit.Assert.fail; 23 import static org.junit.Assume.assumeFalse; 24 import static org.robolectric.testapp.R.color.test_ARGB8; 25 import static org.robolectric.testapp.R.color.test_RGB8; 26 27 import android.content.Context; 28 import android.graphics.Bitmap; 29 import android.graphics.BitmapFactory; 30 import android.graphics.Color; 31 import android.graphics.Typeface; 32 import android.graphics.drawable.AnimationDrawable; 33 import android.graphics.drawable.BitmapDrawable; 34 import android.graphics.drawable.ColorDrawable; 35 import android.graphics.drawable.Drawable; 36 import android.graphics.drawable.NinePatchDrawable; 37 import android.graphics.fonts.Font; 38 import android.graphics.fonts.FontFamily; 39 import android.os.Build; 40 import android.util.AttributeSet; 41 import android.util.TypedValue; 42 import android.util.Xml; 43 import androidx.test.core.app.ApplicationProvider; 44 import androidx.test.ext.junit.runners.AndroidJUnit4; 45 import androidx.test.filters.SdkSuppress; 46 import com.google.common.collect.Range; 47 import java.io.IOException; 48 import java.io.InputStream; 49 import java.lang.reflect.Method; 50 import org.junit.Before; 51 import org.junit.Ignore; 52 import org.junit.Test; 53 import org.junit.runner.RunWith; 54 import org.robolectric.annotation.Config; 55 import org.robolectric.testapp.R; 56 import org.xmlpull.v1.XmlPullParser; 57 import org.xmlpull.v1.XmlPullParserException; 58 59 /** Compatibility test for {@link Resources} */ 60 @RunWith(AndroidJUnit4.class) 61 public class ResourcesTest { 62 private Resources resources; 63 private Context context; 64 65 @Before setup()66 public void setup() { 67 context = ApplicationProvider.getApplicationContext(); 68 resources = context.getResources(); 69 } 70 71 @Test getString()72 public void getString() { 73 assertThat(resources.getString(R.string.hello)).isEqualTo("Hello"); 74 assertThat(resources.getString(R.string.say_it_with_item)).isEqualTo("flowers"); 75 } 76 77 @Test getString_withReference()78 public void getString_withReference() { 79 assertThat(resources.getString(R.string.greeting)).isEqualTo("Howdy"); 80 } 81 82 @Test getString_withInterpolation()83 public void getString_withInterpolation() { 84 assertThat(resources.getString(R.string.interpolate, "value")).isEqualTo("Here is a value!"); 85 } 86 87 @Test getString_withHtml()88 public void getString_withHtml() { 89 assertThat(resources.getString(R.string.some_html, "value")).isEqualTo("Hello, world"); 90 } 91 92 @Test getString_withSurroundingQuotes()93 public void getString_withSurroundingQuotes() { 94 assertThat(resources.getString(R.string.surrounding_quotes, "value")).isEqualTo("This'll work"); 95 } 96 97 @Test getStringWithEscapedApostrophes()98 public void getStringWithEscapedApostrophes() { 99 assertThat(resources.getString(R.string.escaped_apostrophe)).isEqualTo("This'll also work"); 100 } 101 102 @Test getStringWithEscapedQuotes()103 public void getStringWithEscapedQuotes() { 104 assertThat(resources.getString(R.string.escaped_quotes)).isEqualTo("Click \"OK\""); 105 } 106 107 @Test getString_StringWithInlinedQuotesAreStripped()108 public void getString_StringWithInlinedQuotesAreStripped() { 109 assertThat(resources.getString(R.string.bad_example)).isEqualTo("This is a bad string."); 110 } 111 112 @Test getStringShouldStripNewLines()113 public void getStringShouldStripNewLines() { 114 assertThat(resources.getString(R.string.leading_and_trailing_new_lines)).isEqualTo("Some text"); 115 } 116 117 @Test preserveEscapedNewlineAndTab()118 public void preserveEscapedNewlineAndTab() { 119 assertThat(resources.getString(R.string.new_lines_and_tabs, 4)).isEqualTo("4\tmph\nfaster"); 120 } 121 122 @Test getStringShouldConvertCodePoints()123 public void getStringShouldConvertCodePoints() { 124 assertThat(resources.getString(R.string.non_breaking_space)) 125 .isEqualTo("Closing" + " soon:\u00A05pm"); 126 assertThat(resources.getString(R.string.space)).isEqualTo("Closing soon: 5pm"); 127 } 128 129 @Test getMultilineLayoutResource_shouldResolveLayoutReferencesWithLineBreaks()130 public void getMultilineLayoutResource_shouldResolveLayoutReferencesWithLineBreaks() { 131 // multiline_layout is a layout reference to activity_main layout. 132 TypedValue multilineLayoutValue = new TypedValue(); 133 resources.getValue(R.layout.multiline_layout, multilineLayoutValue, true /* resolveRefs */); 134 TypedValue mainActivityLayoutValue = new TypedValue(); 135 resources.getValue(R.layout.activity_main, mainActivityLayoutValue, false /* resolveRefs */); 136 assertThat(multilineLayoutValue.string).isEqualTo(mainActivityLayoutValue.string); 137 } 138 139 @Test getText_withHtml()140 public void getText_withHtml() { 141 assertThat(resources.getText(R.string.some_html, "value").toString()).isEqualTo("Hello, world"); 142 // TODO: Raw resources have lost the tags early, but the following call should return a 143 // SpannedString 144 // assertThat(resources.getText(R.string.some_html)).isInstanceOf(SpannedString.class); 145 } 146 147 @Test getText_plainString()148 public void getText_plainString() { 149 assertThat(resources.getText(R.string.hello, "value").toString()).isEqualTo("Hello"); 150 assertThat(resources.getText(R.string.hello)).isInstanceOf(String.class); 151 } 152 153 @Test getText_withLayoutId()154 public void getText_withLayoutId() { 155 // This isn't _really_ supported by the platform (gives a lint warning that getText() expects a 156 // String resource type 157 // but the actual platform behaviour is to return a string that equals 158 // "res/layout/layout_file.xml" so the current 159 // Robolectric behaviour deviates from the platform as we append the full file path from the 160 // current working directory. 161 String textString = resources.getText(R.layout.different_screen_sizes, "value").toString(); 162 assertThat(textString).containsMatch("/different_screen_sizes.xml$"); 163 // If we run tests on devices with different config, the resource system will select different 164 // layout directories. 165 assertThat(textString).containsMatch("^res/layout"); 166 } 167 168 @Test getStringArray()169 public void getStringArray() { 170 assertThat(resources.getStringArray(R.array.items)).isEqualTo(new String[] {"foo", "bar"}); 171 assertThat(resources.getStringArray(R.array.greetings)) 172 .isEqualTo(new String[] {"hola", "Hello"}); 173 } 174 175 @Test withIdReferenceEntry_obtainTypedArray()176 public void withIdReferenceEntry_obtainTypedArray() { 177 TypedArray typedArray = resources.obtainTypedArray(R.array.typed_array_with_resource_id); 178 assertThat(typedArray.length()).isEqualTo(2); 179 180 assertThat(typedArray.getResourceId(0, 0)).isEqualTo(R.id.id_declared_in_item_tag); 181 assertThat(typedArray.getResourceId(1, 0)).isEqualTo(R.id.id_declared_in_layout); 182 } 183 184 @Test obtainTypedArray()185 public void obtainTypedArray() { 186 final TypedArray valuesTypedArray = resources.obtainTypedArray(R.array.typed_array_values); 187 assertThat(valuesTypedArray.getString(0)).isEqualTo("abcdefg"); 188 assertThat(valuesTypedArray.getInt(1, 0)).isEqualTo(3875); 189 assertThat(valuesTypedArray.getInteger(1, 0)).isEqualTo(3875); 190 assertThat(valuesTypedArray.getFloat(2, 0.0f)).isEqualTo(2.0f); 191 assertThat(valuesTypedArray.getColor(3, Color.BLACK)).isEqualTo(Color.MAGENTA); 192 assertThat(valuesTypedArray.getColor(4, Color.BLACK)).isEqualTo(Color.parseColor("#00ffff")); 193 assertThat(valuesTypedArray.getDimension(5, 0.0f)) 194 .isEqualTo(applyDimension(COMPLEX_UNIT_PX, 8, resources.getDisplayMetrics())); 195 assertThat(valuesTypedArray.getDimension(6, 0.0f)) 196 .isEqualTo(applyDimension(COMPLEX_UNIT_DIP, 12, resources.getDisplayMetrics())); 197 assertThat(valuesTypedArray.getDimension(7, 0.0f)) 198 .isEqualTo(applyDimension(COMPLEX_UNIT_DIP, 6, resources.getDisplayMetrics())); 199 assertThat(valuesTypedArray.getDimension(8, 0.0f)) 200 .isEqualTo(applyDimension(COMPLEX_UNIT_MM, 3, resources.getDisplayMetrics())); 201 assertThat(valuesTypedArray.getDimension(9, 0.0f)) 202 .isEqualTo(applyDimension(COMPLEX_UNIT_IN, 4, resources.getDisplayMetrics())); 203 assertThat(valuesTypedArray.getDimension(10, 0.0f)) 204 .isEqualTo(applyDimension(COMPLEX_UNIT_SP, 36, resources.getDisplayMetrics())); 205 assertThat(valuesTypedArray.getDimension(11, 0.0f)) 206 .isEqualTo(applyDimension(COMPLEX_UNIT_PT, 18, resources.getDisplayMetrics())); 207 208 final TypedArray refsTypedArray = resources.obtainTypedArray(R.array.typed_array_references); 209 assertThat(refsTypedArray.getString(0)).isEqualTo("apple"); 210 assertThat(refsTypedArray.getString(1)).isEqualTo("banana"); 211 assertThat(refsTypedArray.getInt(2, 0)).isEqualTo(5); 212 assertThat(refsTypedArray.getBoolean(3, false)).isTrue(); 213 214 assertThat(refsTypedArray.getResourceId(8, 0)).isEqualTo(R.array.string_array_values); 215 assertThat(refsTypedArray.getTextArray(8)) 216 .asList() 217 .containsAtLeast( 218 "abcdefg", 219 "3875", 220 "2.0", 221 "#ffff00ff", 222 "#00ffff", 223 "8px", 224 "12dp", 225 "6dip", 226 "3mm", 227 "4in", 228 "36sp", 229 "18pt"); 230 231 assertThat(refsTypedArray.getResourceId(9, 0)).isEqualTo(R.style.Theme_Robolectric); 232 } 233 234 @Test getInt()235 public void getInt() { 236 assertThat(resources.getInteger(R.integer.meaning_of_life)).isEqualTo(42); 237 assertThat(resources.getInteger(R.integer.test_integer1)).isEqualTo(2000); 238 assertThat(resources.getInteger(R.integer.test_integer2)).isEqualTo(9); 239 assertThat(resources.getInteger(R.integer.test_large_hex)).isEqualTo(-65536); 240 assertThat(resources.getInteger(R.integer.test_value_with_zero)).isEqualTo(7210); 241 assertThat(resources.getInteger(R.integer.meaning_of_life_as_item)).isEqualTo(42); 242 } 243 244 @Test getInt_withReference()245 public void getInt_withReference() { 246 assertThat(resources.getInteger(R.integer.reference_to_meaning_of_life)).isEqualTo(42); 247 } 248 249 @Test getIntArray()250 public void getIntArray() { 251 assertThat(resources.getIntArray(R.array.empty_int_array)).isEqualTo(new int[] {}); 252 assertThat(resources.getIntArray(R.array.zero_to_four_int_array)) 253 .isEqualTo(new int[] {0, 1, 2, 3, 4}); 254 assertThat(resources.getIntArray(R.array.with_references_int_array)) 255 .isEqualTo(new int[] {0, 2000, 1}); 256 assertThat(resources.getIntArray(R.array.referenced_colors_int_array)) 257 .isEqualTo(new int[] {0x1, 0xFFFFFFFF, 0xFF000000, 0xFFF5F5F5, 0x802C76AD}); 258 } 259 260 @Test getBoolean()261 public void getBoolean() { 262 assertThat(resources.getBoolean(R.bool.false_bool_value)).isEqualTo(false); 263 assertThat(resources.getBoolean(R.bool.true_as_item)).isEqualTo(true); 264 } 265 266 @Test getBoolean_withReference()267 public void getBoolean_withReference() { 268 assertThat(resources.getBoolean(R.bool.reference_to_true)).isEqualTo(true); 269 } 270 271 @Test getDimension()272 public void getDimension() { 273 assertThat(resources.getDimension(R.dimen.test_dip_dimen)) 274 .isEqualTo(applyDimension(COMPLEX_UNIT_DIP, 20, resources.getDisplayMetrics())); 275 assertThat(resources.getDimension(R.dimen.test_dp_dimen)) 276 .isEqualTo(applyDimension(COMPLEX_UNIT_DIP, 8, resources.getDisplayMetrics())); 277 assertThat(resources.getDimension(R.dimen.test_in_dimen)) 278 .isEqualTo(applyDimension(COMPLEX_UNIT_IN, 99, resources.getDisplayMetrics())); 279 assertThat(resources.getDimension(R.dimen.test_mm_dimen)) 280 .isEqualTo(applyDimension(COMPLEX_UNIT_MM, 42, resources.getDisplayMetrics())); 281 assertThat(resources.getDimension(R.dimen.test_px_dimen)) 282 .isEqualTo(applyDimension(COMPLEX_UNIT_PX, 15, resources.getDisplayMetrics())); 283 assertThat(resources.getDimension(R.dimen.test_pt_dimen)) 284 .isEqualTo(applyDimension(COMPLEX_UNIT_PT, 12, resources.getDisplayMetrics())); 285 assertThat(resources.getDimension(R.dimen.test_sp_dimen)) 286 .isEqualTo(applyDimension(COMPLEX_UNIT_SP, 5, resources.getDisplayMetrics())); 287 } 288 289 @Test getDimensionPixelSize()290 public void getDimensionPixelSize() { 291 assertThat(resources.getDimensionPixelSize(R.dimen.test_dip_dimen)) 292 .isIn(onePixelOf(convertDimension(COMPLEX_UNIT_DIP, 20))); 293 assertThat(resources.getDimensionPixelSize(R.dimen.test_dp_dimen)) 294 .isIn(onePixelOf(convertDimension(COMPLEX_UNIT_DIP, 8))); 295 assertThat(resources.getDimensionPixelSize(R.dimen.test_in_dimen)) 296 .isIn(onePixelOf(convertDimension(COMPLEX_UNIT_IN, 99))); 297 assertThat(resources.getDimensionPixelSize(R.dimen.test_mm_dimen)) 298 .isIn(onePixelOf(convertDimension(COMPLEX_UNIT_MM, 42))); 299 assertThat(resources.getDimensionPixelSize(R.dimen.test_px_dimen)) 300 .isIn(onePixelOf(convertDimension(COMPLEX_UNIT_PX, 15))); 301 assertThat(resources.getDimensionPixelSize(R.dimen.test_pt_dimen)) 302 .isIn(onePixelOf(convertDimension(COMPLEX_UNIT_PT, 12))); 303 assertThat(resources.getDimensionPixelSize(R.dimen.test_sp_dimen)) 304 .isIn(onePixelOf(convertDimension(COMPLEX_UNIT_SP, 5))); 305 } 306 onePixelOf(int i)307 private static Range<Integer> onePixelOf(int i) { 308 return Range.closed(i - 1, i + 1); 309 } 310 311 @Test getDimensionPixelOffset()312 public void getDimensionPixelOffset() { 313 assertThat(resources.getDimensionPixelOffset(R.dimen.test_dip_dimen)) 314 .isEqualTo(convertDimension(COMPLEX_UNIT_DIP, 20)); 315 assertThat(resources.getDimensionPixelOffset(R.dimen.test_dp_dimen)) 316 .isEqualTo(convertDimension(COMPLEX_UNIT_DIP, 8)); 317 assertThat(resources.getDimensionPixelOffset(R.dimen.test_in_dimen)) 318 .isEqualTo(convertDimension(COMPLEX_UNIT_IN, 99)); 319 assertThat(resources.getDimensionPixelOffset(R.dimen.test_mm_dimen)) 320 .isEqualTo(convertDimension(COMPLEX_UNIT_MM, 42)); 321 assertThat(resources.getDimensionPixelOffset(R.dimen.test_px_dimen)) 322 .isEqualTo(convertDimension(COMPLEX_UNIT_PX, 15)); 323 assertThat(resources.getDimensionPixelOffset(R.dimen.test_pt_dimen)) 324 .isEqualTo(convertDimension(COMPLEX_UNIT_PT, 12)); 325 assertThat(resources.getDimensionPixelOffset(R.dimen.test_sp_dimen)) 326 .isEqualTo(convertDimension(COMPLEX_UNIT_SP, 5)); 327 } 328 convertDimension(int unit, float value)329 private int convertDimension(int unit, float value) { 330 return (int) applyDimension(unit, value, resources.getDisplayMetrics()); 331 } 332 333 @Test getDimension_withReference()334 public void getDimension_withReference() { 335 assertThat(resources.getBoolean(R.bool.reference_to_true)).isEqualTo(true); 336 } 337 338 @Test getStringArray_shouldThrowExceptionIfNotFound()339 public void getStringArray_shouldThrowExceptionIfNotFound() { 340 assertThrows(Resources.NotFoundException.class, () -> resources.getStringArray(-1)); 341 } 342 343 @Test getIntegerArray_shouldThrowExceptionIfNotFound()344 public void getIntegerArray_shouldThrowExceptionIfNotFound() { 345 assertThrows(Resources.NotFoundException.class, () -> resources.getIntArray(-1)); 346 } 347 348 @Test getQuantityString()349 public void getQuantityString() { 350 assertThat(resources.getQuantityString(R.plurals.beer, 1)).isEqualTo("a beer"); 351 assertThat(resources.getQuantityString(R.plurals.beer, 2)).isEqualTo("some beers"); 352 assertThat(resources.getQuantityString(R.plurals.beer, 3)).isEqualTo("some beers"); 353 } 354 355 @Test getQuantityText()356 public void getQuantityText() { 357 // Feature not supported in legacy (raw) resource mode. 358 assumeFalse(isRobolectricLegacyMode()); 359 360 assertThat(resources.getQuantityText(R.plurals.beer, 1)).isEqualTo("a beer"); 361 assertThat(resources.getQuantityText(R.plurals.beer, 2)).isEqualTo("some beers"); 362 assertThat(resources.getQuantityText(R.plurals.beer, 3)).isEqualTo("some beers"); 363 } 364 365 @Test getFraction()366 public void getFraction() { 367 final int myself = 300; 368 final int myParent = 600; 369 assertThat(resources.getFraction(R.fraction.half, myself, myParent)).isEqualTo(150f); 370 assertThat(resources.getFraction(R.fraction.half_of_parent, myself, myParent)).isEqualTo(300f); 371 372 assertThat(resources.getFraction(R.fraction.quarter_as_item, myself, myParent)).isEqualTo(75f); 373 assertThat(resources.getFraction(R.fraction.quarter_of_parent_as_item, myself, myParent)) 374 .isEqualTo(150f); 375 376 assertThat(resources.getFraction(R.fraction.fifth_as_reference, myself, myParent)) 377 .isWithin(0.01f) 378 .of(60f); 379 assertThat(resources.getFraction(R.fraction.fifth_of_parent_as_reference, myself, myParent)) 380 .isWithin(0.01f) 381 .of(120f); 382 } 383 384 @Test testConfiguration()385 public void testConfiguration() { 386 Configuration configuration = resources.getConfiguration(); 387 assertThat(configuration).isNotNull(); 388 assertThat(configuration.locale).isNotNull(); 389 } 390 391 @Test testConfigurationReturnsTheSameInstance()392 public void testConfigurationReturnsTheSameInstance() { 393 assertThat(resources.getConfiguration()).isSameInstanceAs(resources.getConfiguration()); 394 } 395 396 @Test testNewTheme()397 public void testNewTheme() { 398 assertThat(resources.newTheme()).isNotNull(); 399 } 400 401 @Test testGetDrawableNullRClass()402 public void testGetDrawableNullRClass() { 403 assertThrows( 404 Resources.NotFoundException.class, 405 () -> assertThat(resources.getDrawable(-12345)).isInstanceOf(BitmapDrawable.class)); 406 } 407 408 @Test testGetAnimationDrawable()409 public void testGetAnimationDrawable() { 410 assertThat(resources.getDrawable(R.anim.animation_list)).isInstanceOf(AnimationDrawable.class); 411 } 412 413 @Test testGetColorDrawable()414 public void testGetColorDrawable() { 415 Drawable drawable = resources.getDrawable(R.color.color_with_alpha); 416 assertThat(drawable).isInstanceOf(ColorDrawable.class); 417 assertThat(((ColorDrawable) drawable).getColor()).isEqualTo(0x802C76AD); 418 } 419 420 @Test getColor()421 public void getColor() { 422 assertThat(resources.getColor(R.color.color_with_alpha)).isEqualTo(0x802C76AD); 423 } 424 425 @Test getColor_withReference()426 public void getColor_withReference() { 427 assertThat(resources.getColor(R.color.background)).isEqualTo(0xfff5f5f5); 428 } 429 430 @Test testGetColor_Missing()431 public void testGetColor_Missing() { 432 assertThrows(Resources.NotFoundException.class, () -> resources.getColor(11234)); 433 } 434 435 @Test testGetColorStateList()436 public void testGetColorStateList() { 437 assertThat(resources.getColorStateList(R.color.color_state_list)) 438 .isInstanceOf(ColorStateList.class); 439 } 440 441 @Test testGetBitmapDrawable()442 public void testGetBitmapDrawable() { 443 assertThat(resources.getDrawable(R.drawable.an_image)).isInstanceOf(BitmapDrawable.class); 444 } 445 446 @Test testGetNinePatchDrawable()447 public void testGetNinePatchDrawable() { 448 assertThat(resources.getDrawable(R.drawable.nine_patch_drawable)) 449 .isInstanceOf(NinePatchDrawable.class); 450 } 451 452 @Test testGetBitmapDrawableForUnknownId()453 public void testGetBitmapDrawableForUnknownId() { 454 assertThrows( 455 Resources.NotFoundException.class, 456 () -> 457 assertThat(resources.getDrawable(Integer.MAX_VALUE)) 458 .isInstanceOf(BitmapDrawable.class)); 459 } 460 461 @Test testGetNinePatchDrawableIntrinsicWidth()462 public void testGetNinePatchDrawableIntrinsicWidth() { 463 float density = resources.getDisplayMetrics().density; 464 NinePatchDrawable ninePatchDrawable = 465 (NinePatchDrawable) resources.getDrawable(R.drawable.nine_patch_drawable); 466 // Use Math.round to convert calculated float width to int, 467 // see NinePatchDrawable#scaleFromDensity. 468 assertThat(ninePatchDrawable.getIntrinsicWidth()).isEqualTo(Math.round(98.0f * density)); 469 } 470 471 @Test testGetIdentifier()472 public void testGetIdentifier() { 473 474 final String resourceType = "string"; 475 final String packageName = context.getPackageName(); 476 477 final String resourceName = "hello"; 478 final int resId1 = resources.getIdentifier(resourceName, resourceType, packageName); 479 assertThat(resId1).isEqualTo(R.string.hello); 480 481 final String typedResourceName = resourceType + "/" + resourceName; 482 final int resId2 = resources.getIdentifier(typedResourceName, resourceType, packageName); 483 assertThat(resId2).isEqualTo(R.string.hello); 484 485 final String fqn = packageName + ":" + typedResourceName; 486 final int resId3 = resources.getIdentifier(fqn, resourceType, packageName); 487 assertThat(resId3).isEqualTo(R.string.hello); 488 } 489 490 @Test getIdentifier()491 public void getIdentifier() { 492 String string = resources.getString(R.string.hello); 493 assertThat(string).isEqualTo("Hello"); 494 495 int id = resources.getIdentifier("hello", "string", context.getPackageName()); 496 assertThat(id).isEqualTo(R.string.hello); 497 498 String hello = resources.getString(id); 499 assertThat(hello).isEqualTo("Hello"); 500 } 501 502 @Test getIdentifier_nonExistantResource()503 public void getIdentifier_nonExistantResource() { 504 int id = resources.getIdentifier("just_alot_of_crap", "string", context.getPackageName()); 505 assertThat(id).isEqualTo(0); 506 } 507 508 @Test getIdentifier_material()509 public void getIdentifier_material() { 510 int id = Resources.getSystem().getIdentifier("btn_check_material_anim", "drawable", "android"); 511 assertThat(id).isGreaterThan(0); 512 } 513 514 /** 515 * Public framework symbols are defined here: 516 * https://android.googlesource.com/platform/frameworks/base/+/master/core/res/res/values/public.xml 517 * Private framework symbols are defined here: 518 * https://android.googlesource.com/platform/frameworks/base/+/master/core/res/res/values/symbols.xml 519 * 520 * <p>These generate android.R and com.android.internal.R respectively, when Framework Java code 521 * does not need to reference a framework resource it will not have an R value generated. 522 * Robolectric is then missing an identifier for this resource so we must generate a placeholder 523 * ourselves. 524 */ 525 @Test shouldGenerateIdsForResourcesThatAreMissingRValues()526 public void shouldGenerateIdsForResourcesThatAreMissingRValues() { 527 int identifierMissingFromRFile = 528 resources.getIdentifier("secondary_text_material_dark", "color", "android"); 529 530 // We expect Robolectric to generate a placeholder identifier where one was not generated in the 531 // android R files. 532 assertThat(identifierMissingFromRFile).isNotEqualTo(0); 533 534 // We expect to be able to successfully android:color/secondary_text_material_dark to a 535 // ColorStateList. 536 assertThat(resources.getColorStateList(identifierMissingFromRFile)).isNotNull(); 537 } 538 539 @Test getSystemShouldReturnSystemResources()540 public void getSystemShouldReturnSystemResources() { 541 assertThat(Resources.getSystem()).isInstanceOf(Resources.class); 542 } 543 544 @Test multipleCallsToGetSystemShouldReturnSameInstance()545 public void multipleCallsToGetSystemShouldReturnSameInstance() { 546 assertThat(Resources.getSystem()).isEqualTo(Resources.getSystem()); 547 } 548 549 @Test applicationResourcesShouldHaveBothSystemAndLocalValues()550 public void applicationResourcesShouldHaveBothSystemAndLocalValues() { 551 assertThat(context.getResources().getString(android.R.string.copy)).isEqualTo("Copy"); 552 assertThat(context.getResources().getString(R.string.copy)).isEqualTo("Local Copy"); 553 } 554 555 @Test systemResourcesShouldReturnCorrectSystemId()556 public void systemResourcesShouldReturnCorrectSystemId() { 557 assertThat(Resources.getSystem().getIdentifier("copy", "string", "android")) 558 .isEqualTo(android.R.string.copy); 559 } 560 561 @Test systemResourcesShouldReturnZeroForLocalId()562 public void systemResourcesShouldReturnZeroForLocalId() { 563 assertThat(Resources.getSystem().getIdentifier("copy", "string", context.getPackageName())) 564 .isEqualTo(0); 565 } 566 567 @Test testGetXml()568 public void testGetXml() throws Exception { 569 XmlResourceParser parser = resources.getXml(R.xml.preferences); 570 assertThat(parser).isNotNull(); 571 assertThat(findRootTag(parser)).isEqualTo("PreferenceScreen"); 572 573 parser = resources.getXml(R.layout.custom_layout); 574 assertThat(parser).isNotNull(); 575 assertThat(findRootTag(parser)).isEqualTo("org.robolectric.android.CustomView"); 576 577 parser = resources.getXml(R.menu.test); 578 assertThat(parser).isNotNull(); 579 assertThat(findRootTag(parser)).isEqualTo("menu"); 580 581 parser = resources.getXml(R.drawable.rainbow); 582 assertThat(parser).isNotNull(); 583 assertThat(findRootTag(parser)).isEqualTo("layer-list"); 584 585 parser = resources.getXml(R.anim.test_anim_1); 586 assertThat(parser).isNotNull(); 587 assertThat(findRootTag(parser)).isEqualTo("set"); 588 589 parser = resources.getXml(R.color.color_state_list); 590 assertThat(parser).isNotNull(); 591 assertThat(findRootTag(parser)).isEqualTo("selector"); 592 } 593 594 @Test testGetXml_nonexistentResource()595 public void testGetXml_nonexistentResource() { 596 assertThrows(Resources.NotFoundException.class, () -> resources.getXml(0)); 597 } 598 599 @Test testGetXml_nonxmlfile()600 public void testGetXml_nonxmlfile() { 601 assertThrows(Resources.NotFoundException.class, () -> resources.getXml(R.drawable.an_image)); 602 } 603 604 @Test testGetXml_notNPEAfterClose()605 public void testGetXml_notNPEAfterClose() { 606 XmlResourceParser parser = resources.getXml(R.xml.preferences); 607 parser.close(); 608 // the following methods should not NPE if the XmlResourceParser has been closed. 609 assertThat(parser.getName()).isNull(); 610 assertThat(parser.getNamespace()).isEmpty(); 611 assertThat(parser.getText()).isNull(); 612 } 613 614 @Test openRawResource_shouldLoadRawResources()615 public void openRawResource_shouldLoadRawResources() { 616 InputStream resourceStream = resources.openRawResource(R.raw.raw_resource); 617 assertThat(resourceStream).isNotNull(); 618 // assertThat(TestUtil.readString(resourceStream)).isEqualTo("raw txt file contents"); 619 } 620 621 @Test openRawResource_shouldLoadDrawables()622 public void openRawResource_shouldLoadDrawables() { 623 InputStream resourceStream = resources.openRawResource(R.drawable.an_image); 624 Bitmap bitmap = BitmapFactory.decodeStream(resourceStream); 625 assertThat(bitmap.getHeight()).isEqualTo(53); 626 assertThat(bitmap.getWidth()).isEqualTo(64); 627 } 628 629 @Test openRawResource_withNonFile_throwsNotFoundException()630 public void openRawResource_withNonFile_throwsNotFoundException() { 631 try { 632 resources.openRawResource(R.string.hello); 633 fail("should throw"); 634 } catch (Resources.NotFoundException e) { 635 // cool 636 } 637 638 try { 639 resources.openRawResource(R.string.hello, new TypedValue()); 640 fail("should throw"); 641 } catch (Resources.NotFoundException e) { 642 // cool 643 } 644 645 try { 646 resources.openRawResource(-1234, new TypedValue()); 647 fail("should throw"); 648 } catch (Resources.NotFoundException e) { 649 // cool 650 } 651 } 652 653 @Test openRawResourceFd_withNonCompressedFile_returnsNotNull()654 public void openRawResourceFd_withNonCompressedFile_returnsNotNull() throws IOException { 655 // This test will run on non-legacy resource mode in Robolectric environment. 656 // To test behavior on legacy mode environment, please see ShadowResourceTest. 657 try (AssetFileDescriptor afd = resources.openRawResourceFd(R.raw.raw_resource)) { 658 assertThat(afd).isNotNull(); 659 } 660 } 661 662 @Test openRawResourceFd_withNonFile_throwsNotFoundException()663 public void openRawResourceFd_withNonFile_throwsNotFoundException() { 664 try { 665 resources.openRawResourceFd(R.string.hello); 666 fail("should throw"); 667 } catch (Resources.NotFoundException e) { 668 // cool 669 } 670 671 try { 672 resources.openRawResourceFd(-1234); 673 fail("should throw"); 674 } catch (Resources.NotFoundException e) { 675 // cool 676 } 677 } 678 679 @Test getXml_withNonFile_throwsNotFoundException()680 public void getXml_withNonFile_throwsNotFoundException() { 681 try { 682 resources.getXml(R.string.hello); 683 fail("should throw"); 684 } catch (Resources.NotFoundException e) { 685 // cool 686 } 687 688 try { 689 resources.getXml(-1234); 690 fail("should throw"); 691 } catch (Resources.NotFoundException e) { 692 // cool 693 } 694 } 695 696 @Test themeResolveAttribute_shouldSupportNotDereferencingResource()697 public void themeResolveAttribute_shouldSupportNotDereferencingResource() { 698 TypedValue out = new TypedValue(); 699 700 Resources.Theme theme = resources.newTheme(); 701 theme.applyStyle(R.style.MyBlackTheme, false); 702 703 theme.resolveAttribute(android.R.attr.windowBackground, out, false); 704 assertThat(out.type).isEqualTo(TYPE_REFERENCE); 705 assertThat(out.data).isEqualTo(android.R.color.black); 706 } 707 708 @Test obtainAttributes_shouldReturnValuesFromResources()709 public void obtainAttributes_shouldReturnValuesFromResources() throws Exception { 710 XmlPullParser parser = resources.getXml(R.xml.xml_attrs); 711 parser.next(); 712 parser.next(); 713 AttributeSet attributes = Xml.asAttributeSet(parser); 714 715 TypedArray typedArray = 716 resources.obtainAttributes( 717 attributes, new int[] {android.R.attr.title, android.R.attr.scrollbarFadeDuration}); 718 719 assertThat(typedArray.getString(0)).isEqualTo("Android Title"); 720 assertThat(typedArray.getInt(1, 0)).isEqualTo(1111); 721 typedArray.recycle(); 722 } 723 724 // @Test 725 // public void obtainAttributes_shouldUseReferencedIdFromAttributeSet() throws Exception { 726 // // android:id/mask was introduced in API 21, but it's still possible for apps built against 727 // API 21 to refer to it 728 // // in older runtimes because referenced resource ids are compiled (by aapt) into the binary 729 // XML format. 730 // AttributeSet attributeSet = Robolectric.buildAttributeSet() 731 // .addAttribute(android.R.attr.id, "@android:id/mask").build(); 732 // TypedArray typedArray = resources.obtainAttributes(attributeSet, new 733 // int[]{android.R.attr.id}); 734 // assertThat(typedArray.getResourceId(0, -9)).isEqualTo(android.R.id.mask); 735 // } 736 737 @Test obtainStyledAttributesShouldDereferenceValues()738 public void obtainStyledAttributesShouldDereferenceValues() { 739 Resources.Theme theme = resources.newTheme(); 740 theme.applyStyle(R.style.MyBlackTheme, false); 741 TypedArray arr = theme.obtainStyledAttributes(new int[] {android.R.attr.windowBackground}); 742 TypedValue value = new TypedValue(); 743 arr.getValue(0, value); 744 arr.recycle(); 745 746 assertThat(value.type).isAtLeast(TYPE_FIRST_COLOR_INT); 747 assertThat(value.type).isAtMost(TYPE_LAST_INT); 748 } 749 750 // @Test 751 // public void obtainStyledAttributes_shouldCheckXmlFirst_fromAttributeSetBuilder() throws 752 // Exception { 753 // 754 // // This simulates a ResourceProvider built from a 21+ SDK as viewportHeight / viewportWidth 755 // were introduced in API 21 756 // // but the public ID values they are assigned clash with private com.android.internal.R 757 // values on older SDKs. This 758 // // test ensures that even on older SDKs, on calls to obtainStyledAttributes() Robolectric 759 // will first check for matching 760 // // resource ID values in the AttributeSet before checking the theme. 761 // 762 // AttributeSet attributes = Robolectric.buildAttributeSet() 763 // .addAttribute(android.R.attr.viewportWidth, "12.0") 764 // .addAttribute(android.R.attr.viewportHeight, "24.0") 765 // .build(); 766 // 767 // TypedArray typedArray = context.getTheme().obtainStyledAttributes(attributes, new int[] { 768 // android.R.attr.viewportWidth, 769 // android.R.attr.viewportHeight 770 // }, 0, 0); 771 // assertThat(typedArray.getFloat(0, 0)).isEqualTo(12.0f); 772 // assertThat(typedArray.getFloat(1, 0)).isEqualTo(24.0f); 773 // typedArray.recycle(); 774 // } 775 776 @Test obtainStyledAttributes_shouldCheckXmlFirst_fromXmlLoadedFromResources()777 public void obtainStyledAttributes_shouldCheckXmlFirst_fromXmlLoadedFromResources() 778 throws Exception { 779 780 // This simulates a ResourceProvider built from a 21+ SDK as viewportHeight / viewportWidth were 781 // introduced in API 21 782 // but the public ID values they are assigned clash with private com.android.internal.R values 783 // on older SDKs. This 784 // test ensures that even on older SDKs, on calls to obtainStyledAttributes() Robolectric will 785 // first check for matching 786 // resource ID values in the AttributeSet before checking the theme. 787 788 XmlResourceParser xml = context.getResources().getXml(R.drawable.vector); 789 xml.next(); 790 xml.next(); 791 AttributeSet attributeSet = Xml.asAttributeSet(xml); 792 793 TypedArray typedArray = 794 context 795 .getTheme() 796 .obtainStyledAttributes( 797 attributeSet, 798 new int[] {android.R.attr.viewportWidth, android.R.attr.viewportHeight}, 799 0, 800 0); 801 assertThat(typedArray.getFloat(0, 0)).isEqualTo(12.0f); 802 assertThat(typedArray.getFloat(1, 0)).isEqualTo(24.0f); 803 typedArray.recycle(); 804 } 805 806 @Test whenAttrIsDefinedInRuntimeSdk_getResourceName_findsResource()807 public void whenAttrIsDefinedInRuntimeSdk_getResourceName_findsResource() { 808 assertThat(context.getResources().getResourceName(android.R.attr.viewportHeight)) 809 .isEqualTo("android:attr/viewportHeight"); 810 } 811 812 @Test subClassInitializedOK()813 public void subClassInitializedOK() { 814 SubClassResources subClassResources = new SubClassResources(resources); 815 assertThat(subClassResources.openRawResource(R.raw.raw_resource)).isNotNull(); 816 } 817 818 @Test applyStyleForced()819 public void applyStyleForced() { 820 final Resources.Theme theme = resources.newTheme(); 821 822 theme.applyStyle(R.style.MyBlackTheme, true); 823 TypedArray arr = 824 theme.obtainStyledAttributes( 825 new int[] {android.R.attr.windowBackground, android.R.attr.textColorHint}); 826 827 final TypedValue blackBackgroundColor = new TypedValue(); 828 arr.getValue(0, blackBackgroundColor); 829 assertThat(blackBackgroundColor.resourceId).isEqualTo(android.R.color.black); 830 arr.recycle(); 831 832 theme.applyStyle(R.style.MyBlueTheme, true); 833 arr = 834 theme.obtainStyledAttributes( 835 new int[] { 836 android.R.attr.windowBackground, 837 android.R.attr.textColor, 838 android.R.attr.textColorHint 839 }); 840 841 final TypedValue blueBackgroundColor = new TypedValue(); 842 arr.getValue(0, blueBackgroundColor); 843 assertThat(blueBackgroundColor.resourceId).isEqualTo(R.color.blue); 844 845 final TypedValue blueTextColor = new TypedValue(); 846 arr.getValue(1, blueTextColor); 847 assertThat(blueTextColor.resourceId).isEqualTo(R.color.white); 848 849 final TypedValue blueTextColorHint = new TypedValue(); 850 arr.getValue(2, blueTextColorHint); 851 assertThat(blueTextColorHint.resourceId).isEqualTo(android.R.color.darker_gray); 852 853 arr.recycle(); 854 } 855 856 @Test applyStyleNotForced()857 public void applyStyleNotForced() { 858 final Resources.Theme theme = resources.newTheme(); 859 860 // Apply black theme 861 theme.applyStyle(R.style.MyBlackTheme, true); 862 TypedArray arr = 863 theme.obtainStyledAttributes( 864 new int[] {android.R.attr.windowBackground, android.R.attr.textColorHint}); 865 866 final TypedValue blackBackgroundColor = new TypedValue(); 867 arr.getValue(0, blackBackgroundColor); 868 assertThat(blackBackgroundColor.resourceId).isEqualTo(android.R.color.black); 869 870 final TypedValue blackTextColorHint = new TypedValue(); 871 arr.getValue(1, blackTextColorHint); 872 assertThat(blackTextColorHint.resourceId).isEqualTo(android.R.color.darker_gray); 873 874 arr.recycle(); 875 876 // Apply blue theme 877 theme.applyStyle(R.style.MyBlueTheme, false); 878 arr = 879 theme.obtainStyledAttributes( 880 new int[] { 881 android.R.attr.windowBackground, 882 android.R.attr.textColor, 883 android.R.attr.textColorHint 884 }); 885 886 final TypedValue blueBackgroundColor = new TypedValue(); 887 arr.getValue(0, blueBackgroundColor); 888 assertThat(blueBackgroundColor.resourceId).isEqualTo(android.R.color.black); 889 890 final TypedValue blueTextColor = new TypedValue(); 891 arr.getValue(1, blueTextColor); 892 assertThat(blueTextColor.resourceId).isEqualTo(R.color.white); 893 894 final TypedValue blueTextColorHint = new TypedValue(); 895 arr.getValue(2, blueTextColorHint); 896 assertThat(blueTextColorHint.resourceId).isEqualTo(android.R.color.darker_gray); 897 898 arr.recycle(); 899 } 900 901 @Test getValueShouldClearTypedArrayBetweenCalls()902 public void getValueShouldClearTypedArrayBetweenCalls() { 903 TypedValue outValue = new TypedValue(); 904 905 resources.getValue(R.string.hello, outValue, true); 906 assertThat(outValue.type).isEqualTo(TYPE_STRING); 907 assertThat(outValue.string).isEqualTo(resources.getString(R.string.hello)); 908 // outValue.data is an index into the String block which we don't know for raw xml resources. 909 assertThat(outValue.assetCookie).isNotEqualTo(0); 910 911 resources.getValue(R.color.blue, outValue, true); 912 assertThat(outValue.type).isEqualTo(TYPE_INT_COLOR_RGB8); 913 assertThat(outValue.data).isEqualTo(0xFF0000FF); 914 assertThat(outValue.string).isNull(); 915 // outValue.assetCookie is not supported with raw XML 916 917 resources.getValue(R.integer.loneliest_number, outValue, true); 918 assertThat(outValue.type).isEqualTo(TYPE_INT_DEC); 919 assertThat(outValue.data).isEqualTo(1); 920 assertThat(outValue.string).isNull(); 921 922 resources.getValue(R.bool.true_bool_value, outValue, true); 923 assertThat(outValue.type).isEqualTo(TYPE_INT_BOOLEAN); 924 assertThat(outValue.data).isNotEqualTo(0); // true == traditionally 0xffffffff, -1 in Java but 925 // tests should be checking for non-zero 926 assertThat(outValue.string).isNull(); 927 } 928 929 @Test getXml()930 public void getXml() throws Exception { 931 XmlResourceParser xmlResourceParser = resources.getXml(R.xml.preferences); 932 assertThat(xmlResourceParser).isNotNull(); 933 assertThat(xmlResourceParser.next()).isEqualTo(XmlResourceParser.START_DOCUMENT); 934 assertThat(xmlResourceParser.next()).isEqualTo(XmlResourceParser.START_TAG); 935 assertThat(xmlResourceParser.getName()).isEqualTo("PreferenceScreen"); 936 } 937 938 @Test getXml_shouldParseEmojiCorrectly()939 public void getXml_shouldParseEmojiCorrectly() throws IOException, XmlPullParserException { 940 XmlResourceParser xmlResourceParser = resources.getXml(R.xml.has_emoji); 941 xmlResourceParser.next(); 942 xmlResourceParser.next(); 943 assertThat(xmlResourceParser.getName()).isEqualTo("EmojiRoot"); 944 AttributeSet attributeSet = Xml.asAttributeSet(xmlResourceParser); 945 assertThat(attributeSet.getAttributeValue(null, "label1")).isEqualTo("no emoji"); 946 String pureEmoji = "\uD83D\uDE00"; 947 assertThat(attributeSet.getAttributeValue(null, "label2")).isEqualTo(pureEmoji); 948 assertThat(attributeSet.getAttributeValue(null, "label3")).isEqualTo(pureEmoji); 949 String mixEmojiAndText = "\uD83D\uDE00internal1\uD83D\uDE00internal2\uD83D\uDE00"; 950 assertThat(attributeSet.getAttributeValue(null, "label4")).isEqualTo(mixEmojiAndText); 951 assertThat(attributeSet.getAttributeValue(null, "label5")).isEqualTo(mixEmojiAndText); 952 assertThat(attributeSet.getAttributeValue(null, "label6")) 953 .isEqualTo("don't worry be \uD83D\uDE00"); 954 } 955 956 @Test whenMissingXml_throwNotFoundException()957 public void whenMissingXml_throwNotFoundException() { 958 try { 959 resources.getXml(0x3038); 960 fail(); 961 } catch (Resources.NotFoundException e) { 962 assertThat(e.getMessage()).contains("Resource ID #0x3038"); 963 } 964 } 965 966 @Test stringWithSpaces()967 public void stringWithSpaces() { 968 // this differs from actual Android behavior, which collapses whitespace as "Up to 25 USD" 969 assertThat(resources.getString(R.string.string_with_spaces, "25", "USD")) 970 .isEqualTo("Up to 25 USD"); 971 } 972 973 @Test internalWhiteSpaceShouldBeCollapsed()974 public void internalWhiteSpaceShouldBeCollapsed() { 975 assertThat(resources.getString(R.string.internal_whitespace_blocks)) 976 .isEqualTo("Whitespace in" + " the middle"); 977 assertThat(resources.getString(R.string.internal_newlines)).isEqualTo("Some Newlines"); 978 } 979 980 @Test fontTagWithAttributesShouldBeRead()981 public void fontTagWithAttributesShouldBeRead() { 982 assertThat(resources.getString(R.string.font_tag_with_attribute)) 983 .isEqualTo("This string has a font tag"); 984 } 985 986 @Test linkTagWithAttributesShouldBeRead()987 public void linkTagWithAttributesShouldBeRead() { 988 assertThat(resources.getString(R.string.link_tag_with_attribute)) 989 .isEqualTo("This string has a link tag"); 990 } 991 992 @Test getResourceTypeName_mipmap()993 public void getResourceTypeName_mipmap() { 994 assertThat(resources.getResourceTypeName(R.mipmap.mipmap_reference)).isEqualTo("mipmap"); 995 assertThat(resources.getResourceTypeName(R.mipmap.robolectric)).isEqualTo("mipmap"); 996 } 997 998 @Test getDrawable_mipmapReferencesResolve()999 public void getDrawable_mipmapReferencesResolve() { 1000 Drawable reference = resources.getDrawable(R.mipmap.mipmap_reference); 1001 Drawable original = resources.getDrawable(R.mipmap.robolectric); 1002 1003 assertThat(reference.getMinimumHeight()).isEqualTo(original.getMinimumHeight()); 1004 assertThat(reference.getMinimumWidth()).isEqualTo(original.getMinimumWidth()); 1005 } 1006 1007 @Test 1008 @SdkSuppress(minSdkVersion = Build.VERSION_CODES.O) 1009 @Config(minSdk = Build.VERSION_CODES.O) getDrawable_mipmapReferencesResolveXml()1010 public void getDrawable_mipmapReferencesResolveXml() { 1011 Drawable reference = resources.getDrawable(R.mipmap.robolectric_xml); 1012 Drawable original = resources.getDrawable(R.mipmap.mipmap_reference_xml); 1013 1014 assertThat(reference.getMinimumHeight()).isEqualTo(original.getMinimumHeight()); 1015 assertThat(reference.getMinimumWidth()).isEqualTo(original.getMinimumWidth()); 1016 } 1017 1018 @Test forUntouchedThemes_copyTheme_shouldCopyNothing()1019 public void forUntouchedThemes_copyTheme_shouldCopyNothing() { 1020 Resources.Theme theme1 = resources.newTheme(); 1021 Resources.Theme theme2 = resources.newTheme(); 1022 theme2.setTo(theme1); 1023 } 1024 1025 @Test getResourceIdentifier_shouldReturnValueFromRClass()1026 public void getResourceIdentifier_shouldReturnValueFromRClass() { 1027 assertThat(resources.getIdentifier("id_declared_in_item_tag", "id", context.getPackageName())) 1028 .isEqualTo(R.id.id_declared_in_item_tag); 1029 assertThat( 1030 resources.getIdentifier("id/id_declared_in_item_tag", null, context.getPackageName())) 1031 .isEqualTo(R.id.id_declared_in_item_tag); 1032 assertThat( 1033 resources.getIdentifier( 1034 context.getPackageName() + ":id_declared_in_item_tag", "id", null)) 1035 .isEqualTo(R.id.id_declared_in_item_tag); 1036 assertThat( 1037 resources.getIdentifier( 1038 context.getPackageName() + ":id/id_declared_in_item_tag", "other", "other")) 1039 .isEqualTo(R.id.id_declared_in_item_tag); 1040 } 1041 1042 @Test whenPackageIsUnknown_getResourceIdentifier_shouldReturnZero()1043 public void whenPackageIsUnknown_getResourceIdentifier_shouldReturnZero() { 1044 assertThat(resources.getIdentifier("whatever", "id", "some.unknown.package")).isEqualTo(0); 1045 assertThat(resources.getIdentifier("id/whatever", null, "some.unknown.package")).isEqualTo(0); 1046 assertThat(resources.getIdentifier("some.unknown.package:whatever", "id", null)).isEqualTo(0); 1047 assertThat(resources.getIdentifier("some.unknown.package:id/whatever", "other", "other")) 1048 .isEqualTo(0); 1049 1050 assertThat(resources.getIdentifier("whatever", "drawable", "some.unknown.package")) 1051 .isEqualTo(0); 1052 assertThat(resources.getIdentifier("drawable/whatever", null, "some.unknown.package")) 1053 .isEqualTo(0); 1054 assertThat(resources.getIdentifier("some.unknown.package:whatever", "drawable", null)) 1055 .isEqualTo(0); 1056 assertThat(resources.getIdentifier("some.unknown.package:id/whatever", "other", "other")) 1057 .isEqualTo(0); 1058 } 1059 1060 @Test 1061 @Ignore( 1062 "currently ids are always automatically assigned a value; to fix this we'd need to check " 1063 + "layouts for +@id/___, which is expensive") whenCalledForIdWithNameNotInRClassOrXml_getResourceIdentifier_shouldReturnZero()1064 public void whenCalledForIdWithNameNotInRClassOrXml_getResourceIdentifier_shouldReturnZero() { 1065 assertThat( 1066 resources.getIdentifier( 1067 "org.robolectric:id/idThatDoesntExistAnywhere", "other", "other")) 1068 .isEqualTo(0); 1069 } 1070 1071 @Test 1072 public void whenIdIsAbsentInXmlButPresentInRClass_getResourceIdentifier_shouldReturnIdFromRClass_probablyBecauseItWasDeclaredInALayout()1073 whenIdIsAbsentInXmlButPresentInRClass_getResourceIdentifier_shouldReturnIdFromRClass_probablyBecauseItWasDeclaredInALayout() { 1074 assertThat(resources.getIdentifier("id_declared_in_layout", "id", context.getPackageName())) 1075 .isEqualTo(R.id.id_declared_in_layout); 1076 } 1077 1078 @Test whenResourceIsAbsentInXml_getResourceIdentifier_shouldReturn0()1079 public void whenResourceIsAbsentInXml_getResourceIdentifier_shouldReturn0() { 1080 assertThat(resources.getIdentifier("fictitiousDrawable", "drawable", context.getPackageName())) 1081 .isEqualTo(0); 1082 } 1083 1084 @Test whenResourceIsAbsentInXml_getResourceIdentifier_shouldReturnId()1085 public void whenResourceIsAbsentInXml_getResourceIdentifier_shouldReturnId() { 1086 assertThat(resources.getIdentifier("an_image", "drawable", context.getPackageName())) 1087 .isEqualTo(R.drawable.an_image); 1088 } 1089 1090 @Test whenResourceIsXml_getResourceIdentifier_shouldReturnId()1091 public void whenResourceIsXml_getResourceIdentifier_shouldReturnId() { 1092 assertThat(resources.getIdentifier("preferences", "xml", context.getPackageName())) 1093 .isEqualTo(R.xml.preferences); 1094 } 1095 1096 @Test whenResourceIsRaw_getResourceIdentifier_shouldReturnId()1097 public void whenResourceIsRaw_getResourceIdentifier_shouldReturnId() { 1098 assertThat(resources.getIdentifier("raw_resource", "raw", context.getPackageName())) 1099 .isEqualTo(R.raw.raw_resource); 1100 } 1101 1102 @Test getResourceValue_colorARGB8()1103 public void getResourceValue_colorARGB8() { 1104 TypedValue outValue = new TypedValue(); 1105 resources.getValue(test_ARGB8, outValue, false); 1106 assertThat(outValue.type).isEqualTo(TYPE_INT_COLOR_ARGB8); 1107 assertThat(Color.blue(outValue.data)).isEqualTo(2); 1108 } 1109 1110 @Test getResourceValue_colorRGB8()1111 public void getResourceValue_colorRGB8() { 1112 TypedValue outValue = new TypedValue(); 1113 resources.getValue(test_RGB8, outValue, false); 1114 assertThat(outValue.type).isEqualTo(TYPE_INT_COLOR_RGB8); 1115 assertThat(Color.blue(outValue.data)).isEqualTo(4); 1116 } 1117 1118 @Test getResourceEntryName_forStyle()1119 public void getResourceEntryName_forStyle() { 1120 assertThat(resources.getResourceEntryName(android.R.style.TextAppearance_Small)) 1121 .isEqualTo("TextAppearance.Small"); 1122 } 1123 1124 @Test 1125 @SdkSuppress(minSdkVersion = O) 1126 @Config(minSdk = O) getFont()1127 public void getFont() { 1128 // Feature not supported in legacy (raw) resource mode. 1129 assumeFalse(isRobolectricLegacyMode()); 1130 1131 Typeface typeface = resources.getFont(R.font.vt323_regular); 1132 assertThat(typeface).isNotNull(); 1133 } 1134 1135 @Test 1136 @SdkSuppress(minSdkVersion = O) 1137 @Config(minSdk = O) getFontFamily()1138 public void getFontFamily() { 1139 // Feature not supported in legacy (raw) resource mode. 1140 assumeFalse(isRobolectricLegacyMode()); 1141 1142 Typeface typeface = resources.getFont(R.font.vt323); 1143 assertThat(typeface).isNotNull(); 1144 } 1145 1146 @Test 1147 @SdkSuppress(minSdkVersion = O) 1148 @Config(minSdk = O) getFontFamily_downloadable()1149 public void getFontFamily_downloadable() { 1150 // Feature not supported in legacy (raw) resource mode. 1151 assumeFalse(isRobolectricLegacyMode()); 1152 1153 Typeface typeface = resources.getFont(R.font.downloadable); 1154 assertThat(typeface).isNotNull(); 1155 } 1156 1157 @Test 1158 @SdkSuppress(minSdkVersion = Q) 1159 @Config(minSdk = Q) testFontBuilder()1160 public void testFontBuilder() throws Exception { 1161 // Used to throw `java.io.IOException: Failed to read font contents` 1162 new Font.Builder(context.getResources(), R.font.vt323_regular).build(); 1163 } 1164 1165 @Test 1166 @SdkSuppress(minSdkVersion = Q) 1167 @Config(minSdk = Q) fontFamily_getFont()1168 public void fontFamily_getFont() throws Exception { 1169 Font platformFont = new Font.Builder(resources, R.font.vt323_regular).build(); 1170 FontFamily fontFamily = new FontFamily.Builder(platformFont).build(); 1171 assertThat(fontFamily.getFont(0)).isNotNull(); 1172 } 1173 1174 @Test 1175 @SdkSuppress(minSdkVersion = Q) 1176 @Config(minSdk = Q) getAttributeSetSourceResId()1177 public void getAttributeSetSourceResId() { 1178 XmlResourceParser xmlResourceParser = resources.getXml(R.xml.preferences); 1179 1180 int sourceResId = Resources.getAttributeSetSourceResId(xmlResourceParser); 1181 1182 assertThat(sourceResId).isEqualTo(R.xml.preferences); 1183 } 1184 findRootTag(XmlResourceParser parser)1185 private static String findRootTag(XmlResourceParser parser) throws Exception { 1186 int event; 1187 do { 1188 event = parser.next(); 1189 } while (event != XmlPullParser.START_TAG); 1190 return parser.getName(); 1191 } 1192 1193 private static class SubClassResources extends Resources { SubClassResources(Resources res)1194 public SubClassResources(Resources res) { 1195 super(res.getAssets(), res.getDisplayMetrics(), res.getConfiguration()); 1196 } 1197 } 1198 isRobolectricLegacyMode()1199 private static boolean isRobolectricLegacyMode() { 1200 try { 1201 Class<?> runtimeEnvironmentClass = Class.forName("org.robolectric.RuntimeEnvironment"); 1202 Method useLegacyResourcesMethod = 1203 runtimeEnvironmentClass.getDeclaredMethod("useLegacyResources"); 1204 return (boolean) useLegacyResourcesMethod.invoke(null); 1205 } catch (Exception e) { 1206 return false; 1207 } 1208 } 1209 } 1210