Skip to content

Commit 6e89a6d

Browse files
committed
Check LayerDrawable bounds ourselves
1 parent 564979a commit 6e89a6d

File tree

3 files changed

+48
-19
lines changed

3 files changed

+48
-19
lines changed

features/dd-sdk-android-session-replay/src/main/kotlin/com/datadog/android/sessionreplay/internal/recorder/LayerDrawableExt.kt

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,14 @@ import com.datadog.android.api.InternalLogger
1212

1313
@Suppress("TooGenericExceptionCaught")
1414
internal fun LayerDrawable.safeGetDrawable(index: Int, logger: InternalLogger = InternalLogger.UNBOUND): Drawable? {
15-
return try {
16-
this.getDrawable(index)
17-
} catch (e: IndexOutOfBoundsException) {
18-
// this should never happen
15+
return if (index < 0 || index >= this.numberOfLayers) {
1916
logger.log(
2017
level = InternalLogger.Level.ERROR,
2118
target = InternalLogger.Target.MAINTAINER,
22-
{ "Failed to get drawable from layer" },
23-
e
19+
{ "Failed to get drawable from layer - invalid index passed: $index" }
2420
)
2521
null
22+
} else {
23+
this.getDrawable(index)
2624
}
2725
}

features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/LayerDrawableExtTest.kt

Lines changed: 38 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ internal class LayerDrawableExtTest {
4646
@Test
4747
fun `M return drawable for index W safeGetDrawable()`() {
4848
// Given
49+
whenever(mockLayerDrawable.numberOfLayers)
50+
.thenReturn(1)
4951
whenever(mockLayerDrawable.getDrawable(0))
5052
.thenReturn(mockBitmapDrawable)
5153

@@ -55,20 +57,50 @@ internal class LayerDrawableExtTest {
5557
)
5658

5759
// Then
58-
assertThat(drawable)
59-
.isEqualTo(mockBitmapDrawable)
60+
assertThat(drawable).isEqualTo(mockBitmapDrawable)
6061
}
6162

6263
@Test
63-
fun `M log error W safeGetDrawable() { out of bounds }`() {
64+
fun `M return null W safeGetDrawable() { index below 0 }`() {
6465
// Given
66+
whenever(mockLayerDrawable.numberOfLayers)
67+
.thenReturn(0)
68+
whenever(mockLayerDrawable.getDrawable(any()))
69+
.thenThrow(IndexOutOfBoundsException())
70+
71+
// When
72+
val drawable = mockLayerDrawable.safeGetDrawable(
73+
index = -1,
74+
mockInternalLogger
75+
)
76+
77+
// Then
78+
val captor = argumentCaptor<() -> String>()
79+
verify(mockInternalLogger).log(
80+
level = any(),
81+
target = any(),
82+
captor.capture(),
83+
anyOrNull(),
84+
anyOrNull(),
85+
anyOrNull()
86+
)
87+
assertThat(captor.firstValue.invoke())
88+
.startsWith("Failed to get drawable from layer - invalid index passed")
89+
assertThat(drawable).isNull()
90+
}
91+
92+
@Test
93+
fun `M return null W safeGetDrawable() { index above number of layers }`() {
94+
// Given
95+
whenever(mockLayerDrawable.numberOfLayers)
96+
.thenReturn(0)
6597
whenever(mockLayerDrawable.getDrawable(any()))
6698
.thenThrow(IndexOutOfBoundsException())
6799

68100
// When
69101
val drawable = mockLayerDrawable.safeGetDrawable(
70102
index = 1,
71-
logger = mockInternalLogger
103+
mockInternalLogger
72104
)
73105

74106
// Then
@@ -82,8 +114,7 @@ internal class LayerDrawableExtTest {
82114
anyOrNull()
83115
)
84116
assertThat(captor.firstValue.invoke())
85-
.isEqualTo("Failed to get drawable from layer")
86-
assertThat(drawable)
87-
.isNull()
117+
.startsWith("Failed to get drawable from layer - invalid index passed")
118+
assertThat(drawable).isNull()
88119
}
89120
}

features/dd-sdk-android-session-replay/src/test/kotlin/com/datadog/android/sessionreplay/internal/recorder/base64/Base64LRUCacheTest.kt

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ import org.mockito.Mock
2727
import org.mockito.Mockito.mock
2828
import org.mockito.junit.jupiter.MockitoExtension
2929
import org.mockito.junit.jupiter.MockitoSettings
30-
import org.mockito.kotlin.any
3130
import org.mockito.kotlin.argumentCaptor
3231
import org.mockito.kotlin.whenever
3332
import org.mockito.quality.Strictness
@@ -117,6 +116,7 @@ internal class Base64LRUCacheTest {
117116
val mockRippleDrawable: RippleDrawable = mock()
118117
val mockBgLayer: Drawable = mock()
119118
val mockFgLayer: Drawable = mock()
119+
whenever(mockRippleDrawable.numberOfLayers).thenReturn(2)
120120
whenever(mockRippleDrawable.safeGetDrawable(0))
121121
.thenReturn(mockBgLayer)
122122
whenever(mockRippleDrawable.safeGetDrawable(1))
@@ -138,14 +138,14 @@ internal class Base64LRUCacheTest {
138138
}
139139

140140
@Test
141-
fun `M not generate key prefix W put() { layerDrawable with only one layer }`(forge: Forge) {
141+
fun `M not generate key prefix W put() { layerDrawable with only one layer }`(
142+
@Mock mockRippleDrawable: RippleDrawable,
143+
@Mock mockBgLayer: Drawable,
144+
@StringForgery fakeBase64: String
145+
) {
142146
// Given
143-
val mockRippleDrawable: RippleDrawable = mock()
144-
val mockBgLayer: Drawable = mock()
145-
whenever(mockRippleDrawable.safeGetDrawable(any())).thenReturn(mockBgLayer)
146147
whenever(mockRippleDrawable.numberOfLayers).thenReturn(1)
147148
whenever(mockRippleDrawable.safeGetDrawable(0)).thenReturn(mockBgLayer)
148-
val fakeBase64 = forge.aString()
149149
testedCache.put(mockRippleDrawable, fakeBase64)
150150

151151
val expectedPrefix = System.identityHashCode(mockBgLayer).toString() + "-"

0 commit comments

Comments
 (0)