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