blob: 5de84d80d769c4e221436914bbb04d1c307a1a2f [file] [log] [blame]
package org.robolectric.shadows;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.TruthJUnit.assume;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.robolectric.shadows.ShadowAssetManager.legacyShadowOf;
import static org.robolectric.shadows.ShadowAssetManager.useLegacy;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.util.TypedValue;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.runner.RunWith;
import org.robolectric.R;
import org.robolectric.Robolectric;
import org.robolectric.annotation.Config;
import org.robolectric.shadow.api.Shadow;
import org.robolectric.shadows.ShadowResources.ShadowLegacyTheme;
@RunWith(AndroidJUnit4.class)
public class ShadowAssetManagerTest {
@Rule
public ExpectedException expectedException = ExpectedException.none();
private AssetManager assetManager;
private Resources resources;
@Before
public void setUp() throws Exception {
resources = ApplicationProvider.getApplicationContext().getResources();
assetManager = resources.getAssets();
}
@Test
public void openFd_shouldProvideFileDescriptorForDeflatedAsset() throws Exception {
assume().that(useLegacy()).isFalse();
expectedException.expect(FileNotFoundException.class);
expectedException.expectMessage(
"This file can not be opened as a file descriptor; it is probably compressed");
assetManager.openFd("deflatedAsset.xml");
}
@Test
public void openNonAssetShouldOpenRealAssetFromResources() throws IOException {
InputStream inputStream = assetManager.openNonAsset(0, "res/drawable/an_image.png", 0);
// expect different sizes in binary vs file resources
int bytes = countBytes(inputStream);
if (bytes != 6559 && bytes != 5138) {
fail("Expected 5138 or 6559 bytes for image but got " + bytes);
}
}
@Test
public void openNonAssetShouldOpenFileFromAndroidJar() throws IOException {
String fileName = "res/raw/fallbackring.ogg";
if (useLegacy()) {
// Not the real full path (it's in .m2/repository), but it only cares about the last folder and file name;
// retrieves the uncompressed, un-version-qualified file from raw-res/...
fileName = "jar:" + fileName;
}
InputStream inputStream = assetManager.openNonAsset(0, fileName, 0);
assertThat(countBytes(inputStream)).isEqualTo(14611);
}
@Test
public void openNonAssetShouldThrowExceptionWhenFileDoesNotExist() throws IOException {
assume().that(useLegacy()).isTrue();
expectedException.expect(IOException.class);
expectedException.expectMessage(
"res/drawable/does_not_exist.png");
assetManager.openNonAsset(0, "res/drawable/does_not_exist.png", 0);
}
@Test
public void unknownResourceIdsShouldReportPackagesSearched() throws IOException {
assume().that(useLegacy()).isTrue();
expectedException.expect(Resources.NotFoundException.class);
expectedException.expectMessage("Resource ID #0xffffffff");
resources.newTheme().applyStyle(-1, false);
assetManager.openNonAsset(0, "res/drawable/does_not_exist.png", 0);
}
@Test
public void forSystemResources_unknownResourceIdsShouldReportPackagesSearched()
throws IOException {
assume().that(useLegacy()).isTrue();
expectedException.expect(Resources.NotFoundException.class);
expectedException.expectMessage("Resource ID #0xffffffff");
Resources.getSystem().newTheme().applyStyle(-1, false);
assetManager.openNonAsset(0, "res/drawable/does_not_exist.png", 0);
}
@Test
@Config(qualifiers = "mdpi")
public void openNonAssetShouldOpenCorrectAssetBasedOnQualifierMdpi() throws IOException {
assume().that(useLegacy()).isTrue();
InputStream inputStream = assetManager.openNonAsset(0, "res/drawable/robolectric.png", 0);
assertThat(countBytes(inputStream)).isEqualTo(8141);
}
@Test
@Config(qualifiers = "hdpi")
public void openNonAssetShouldOpenCorrectAssetBasedOnQualifierHdpi() throws IOException {
assume().that(useLegacy()).isTrue();
InputStream inputStream = assetManager.openNonAsset(0, "res/drawable/robolectric.png", 0);
assertThat(countBytes(inputStream)).isEqualTo(23447);
}
// todo: port to ResourcesTest
@Test
public void multiFormatAttributes_integerDecimalValue() {
AttributeSet attributeSet =
Robolectric.buildAttributeSet().addAttribute(R.attr.multiformat, "16").build();
TypedArray typedArray =
resources.obtainAttributes(attributeSet, new int[] {R.attr.multiformat});
TypedValue outValue = new TypedValue();
typedArray.getValue(0, outValue);
assertThat(outValue.type).isEqualTo(TypedValue.TYPE_INT_DEC);
}
// todo: port to ResourcesTest
@Test
public void multiFormatAttributes_integerHexValue() {
AttributeSet attributeSet =
Robolectric.buildAttributeSet().addAttribute(R.attr.multiformat, "0x10").build();
TypedArray typedArray =
resources.obtainAttributes(attributeSet, new int[] {R.attr.multiformat});
TypedValue outValue = new TypedValue();
typedArray.getValue(0, outValue);
assertThat(outValue.type).isEqualTo(TypedValue.TYPE_INT_HEX);
}
// todo: port to ResourcesTest
@Test
public void multiFormatAttributes_stringValue() {
AttributeSet attributeSet =
Robolectric.buildAttributeSet().addAttribute(R.attr.multiformat, "Hello World").build();
TypedArray typedArray =
resources.obtainAttributes(attributeSet, new int[] {R.attr.multiformat});
TypedValue outValue = new TypedValue();
typedArray.getValue(0, outValue);
assertThat(outValue.type).isEqualTo(TypedValue.TYPE_STRING);
}
// todo: port to ResourcesTest
@Test
public void multiFormatAttributes_booleanValue() {
AttributeSet attributeSet =
Robolectric.buildAttributeSet().addAttribute(R.attr.multiformat, "true").build();
TypedArray typedArray =
resources.obtainAttributes(attributeSet, new int[] {R.attr.multiformat});
TypedValue outValue = new TypedValue();
typedArray.getValue(0, outValue);
assertThat(outValue.type).isEqualTo(TypedValue.TYPE_INT_BOOLEAN);
}
@Test
public void attrsToTypedArray_shouldAllowMockedAttributeSets() {
assume().that(useLegacy()).isTrue();
AttributeSet mockAttributeSet = mock(AttributeSet.class);
when(mockAttributeSet.getAttributeCount()).thenReturn(1);
when(mockAttributeSet.getAttributeNameResource(0)).thenReturn(android.R.attr.windowBackground);
when(mockAttributeSet.getAttributeName(0)).thenReturn("android:windowBackground");
when(mockAttributeSet.getAttributeValue(0)).thenReturn("value");
resources.obtainAttributes(mockAttributeSet, new int[]{android.R.attr.windowBackground});
}
@Test
public void whenStyleAttrResolutionFails_attrsToTypedArray_returnsNiceErrorMessage() {
assume().that(useLegacy()).isTrue();
expectedException.expect(RuntimeException.class);
expectedException.expectMessage(
"no value for org.robolectric:attr/styleNotSpecifiedInAnyTheme in theme with applied"
+ " styles: [Style org.robolectric:Theme.Robolectric (and parents)]");
Resources.Theme theme = resources.newTheme();
theme.applyStyle(R.style.Theme_Robolectric, false);
legacyShadowOf(assetManager)
.attrsToTypedArray(
resources,
Robolectric.buildAttributeSet()
.setStyleAttribute("?attr/styleNotSpecifiedInAnyTheme")
.build(),
new int[] {R.attr.string1},
0,
((ShadowLegacyTheme) Shadow.extract(theme)).getNativePtr(),
0);
}
///////////////////////////////
private static int countBytes(InputStream i) throws IOException {
int count = 0;
while (i.read() != -1) {
count++;
}
i.close();
return count;
}
}